#include "service/DispatchService.h"

#include "core/Logger.h"
#include "service/DataUploader.h"
#include "service/tracker/StorageChargePriceTracker.h"
#include "utils/Config.h"

#include <algorithm>
#include <chrono>
#include <cmath>
#include <sstream>
#include <thread>
#include <ctime>

namespace ems {
namespace service {

namespace {

StorageDeviceCommand deriveStorageDeviceCommand(const std::vector<DispatchActionCode>& actions) {
    bool needStart = false;
    bool needStop = false;

    for (auto code : actions) {
        switch (code) {
            case DispatchActionCode::StoreAllPv:
            case DispatchActionCode::StorePartPv:
            case DispatchActionCode::StorageDischargeFull:
            case DispatchActionCode::StorageDischargeControl:
                needStart = true;
                break;
            case DispatchActionCode::PauseStorageCharge:
            case DispatchActionCode::PauseStorageDischarge:
                needStop = true;
                break;
            default:
                break;
        }
    }

    if (needStop) {
        return StorageDeviceCommand::Stop;
    }
    if (needStart) {
        return StorageDeviceCommand::Start;
    }
    return StorageDeviceCommand::None;
}

}  // namespace

// 构造函数：设定初始动作为 IdleAll，避免尚未评估时出现空指令
DispatchService::DispatchService() {
    evaluationIntervalSec_.store(5);
    // 默认让调度处于空闲状态，便于首次评估时有基准动作
    lastAction_.actions.push_back(DispatchActionCode::IdleAll);
    lastAction_.trace.clear();
    
    // 初始化充电价格跟踪器
    chargePriceTracker_.reset(new tracker::StorageChargePriceTracker());
}

// 析构函数：确保线程在对象销毁前被停止
DispatchService::~DispatchService() {
    stop();
}

// 初始化内部缓存及默认状态
bool DispatchService::initialize() {
    std::lock_guard<std::mutex> lock(dataMutex_);
    lastContext_ = DispatchContext{};
    lastAction_.actions.clear();
    lastAction_.actions.push_back(DispatchActionCode::IdleAll);
    lastAction_.trace.clear();
    
    // 从配置读取电池容量和日夜时段
    auto& config = ems::utils::Config::getInstance();
    const double batteryCapacity = config.getInt("battery_capacity_kwh", 100);
    const int dayStart = config.getInt("day_period_start_hour", 6);
    const int dayEnd = config.getInt("day_period_end_hour", 18);
    const double maxSocDelta = config.getInt("max_soc_delta_percent", 5);
    const double storageCostRate = config.getInt("storage_cost_rate", 0);  // 储能损耗成本（元/kWh）
    
    chargePriceTracker_->setBatteryCapacity(batteryCapacity);
    chargePriceTracker_->setDayNightPeriod(dayStart, dayEnd);
    chargePriceTracker_->setMaxSocDelta(maxSocDelta);
    chargePriceTracker_->setStorageCostRate(storageCostRate);
    
    // 初始化时清空上下文并设置默认动作，避免脏数据影响调度判断
    LOG_INFO("DispatchService initialized with empty context");
    return true;
}

// 启动独立调度线程
void DispatchService::start() {
    if (running_.load()) {
        LOG_WARN("DispatchService already running");
        return;
    }

    running_.store(true);
    // 启动独立线程持续评估调度策略
    worker_ = std::thread(&DispatchService::serviceLoop, this);
    LOG_INFO("DispatchService thread started");
}

// 停止调度线程并等待退出
void DispatchService::stop() {
    // 停止评估线程，确保重复调用安全
    if (!running_.load()) {
        return;
    }

    running_.store(false);
    if (worker_.joinable()) {
        // 等待工作线程退出，保证资源安全回收
        worker_.join();
    }
    LOG_INFO("DispatchService thread stopped");
}

// 调整调度评估周期
// seconds: 新的调度周期（秒），需为正数
void DispatchService::setEvaluationInterval(int seconds) {
    if (seconds <= 0) {
        LOG_WARN("DispatchService evaluation interval must be positive, ignore: " << seconds);
        return;
    }
    evaluationIntervalSec_.store(seconds);
    // 支持按需调整评估周期以匹配实时性
}

// 返回最近一次采样的上下文
DispatchContext DispatchService::getLastContext() const {
    std::lock_guard<std::mutex> lock(dataMutex_);
    return lastContext_;
}

// 返回最近一次计算出的动作序列
DispatchAction DispatchService::getLastAction() const {
    std::lock_guard<std::mutex> lock(dataMutex_);
    return lastAction_;
}

// 调度执行主循环
void DispatchService::serviceLoop() {
    // 主循环：按周期采集上下文、计算动作，并缓存结果
    while (running_.load()) {
        const bool enabled = enabled_.load();
        const auto ctx = buildContextSnapshot();
        DispatchAction action;

        if (enabled) {
            action = evaluate(ctx);
        } else {
            action.actions.clear();
            action.actions.push_back(DispatchActionCode::IdleAll);
            action.trace.clear();
            action.trace.push_back("调度未启用");
        }

        {
            std::lock_guard<std::mutex> lock(dataMutex_);
            lastContext_ = ctx;
            lastAction_ = action;
        }

        if (enabled) {
            LOG_INFO("DispatchService evaluated actions: " << toString(action));
        }

        const int interval = evaluationIntervalSec_.load();
        // 间隔睡眠以维持周期运行，同时允许中途停止
        for (int i = 0; i < interval && running_.load(); ++i) {
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
    }
}

// 构造调度上下文占位数据，后续可替换为真实采集
DispatchContext DispatchService::buildContextSnapshot() {
    // 当前示例使用占位符数据，后续可接入真实采集结果
    DispatchContext ctx;
    ctx.load_power_kw = 0.0;                         // 初始化占位值，详见 DispatchContext 注释
    ctx.pv_power_kw = 0.0;                           // 初始化占位值
    ctx.storage_charge_cap_kw = 0.0;                 // 初始化占位值
    ctx.storage_discharge_cap_kw = 0.0;              // 初始化占位值
    ctx.storage_window = StorageWindow::IdleWindow;  // 默认闲置窗口
    ctx.storage_state = StorageState::Idle;          // 默认闲置状态
    ctx.storage_soc = 0.0;                           // 初始化占位值
    auto& config = ems::utils::Config::getInstance();
    const auto& dispatchCfg = config.getDispatch();

    ctx.storage_charge_price = dispatchCfg.storageChargePrice; // 配置：储能历史充电均价
    ctx.pv_feed_price = dispatchCfg.pvFeedPrice;               // 配置：光伏上网电价（元/千瓦时）
    ctx.grid_price_now = dispatchCfg.gridPricePeak;            // 默认使用配置峰值，待 TOU 覆盖
    ctx.grid_price_peak = dispatchCfg.gridPricePeak;           // 配置：峰段电价（如未配置则保持 0）
    ctx.is_peak_period = false;                                // 初始化占位值
    ctx.critical_load_kw = dispatchCfg.criticalLoadKw;         // 配置：关键负载保底功率

    double sampledValue = 0.0;
    if (fetchValueFromCategory("pcs", pvDataKey_, sampledValue)) {
        ctx.pv_power_kw = sampledValue;              // 命中缓存：光伏输出功率（kW）
        ctx.pv_power_valid = true;
    }

    if (fetchValueFromCategory("pcs", "total_active_power", sampledValue)) {
        ctx.load_power_kw = sampledValue;            // 命中缓存：当前系统负载功率（kW）
        ctx.load_power_valid = true;
    }

    if (fetchValueFromCategory("pcs", "storage_charge_cap_kw", sampledValue)) {
        ctx.storage_charge_cap_kw = sampledValue;    // 命中缓存：储能允许的充电功率上限（kW）
        ctx.storage_charge_cap_valid = true;
    }

    if (fetchValueFromCategory("pcs", "storage_discharge_cap_kw", sampledValue)) {
        ctx.storage_discharge_cap_kw = sampledValue; // 命中缓存：储能允许的放电功率上限（kW）
        ctx.storage_discharge_cap_valid = true;
    }

    if (fetchValueFromCategory("pcs", "battery_state_of_charge", sampledValue)) {
        ctx.storage_soc = sampledValue;              // 命中缓存：储能 SOC（%）
        ctx.storage_soc_valid = true;
    }

    if (fetchValueFromCategory("pcs", "storage_state", sampledValue)) {
        const int rawState = static_cast<int>(std::lround(sampledValue));
        ctx.storage_state = mapStorageStateFromRaw(rawState); // 命中缓存：储能实时状态
        ctx.storage_window = deriveWindowFromState(ctx.storage_state);
        ctx.storage_state_valid = true;
    }

    if (config.hasTimeOfUsePrice()) {
        const std::int64_t nowTs = static_cast<std::int64_t>(std::time(nullptr));
        const double touNow = config.getTimeOfUsePrice(nowTs);
        const double touPeak = config.getTimeOfUsePeakPrice(nowTs);
        if (touNow > 0.0) {
            ctx.grid_price_now = touNow;
        }
        if (touPeak > 0.0) {
            ctx.grid_price_peak = touPeak;
        } else if (ctx.grid_price_peak <= 0.0 && touNow > 0.0) {
            ctx.grid_price_peak = touNow;
        }
        ctx.is_peak_period = config.isTimeOfUsePeakPeriod(nowTs);
    }

    // 更新充电价格跟踪器（使用实时 SOC 和价格）
    if (ctx.storage_soc_valid && chargePriceTracker_) {
        const std::int64_t nowTs = static_cast<std::int64_t>(std::time(nullptr));
        chargePriceTracker_->onSample(ctx.storage_soc, nowTs, ctx.pv_feed_price, ctx.grid_price_now);
        
        // 将总平均价写回 storage_charge_price 供调度使用
        const double avgPrice = chargePriceTracker_->getTotalAveragePrice();
        if (avgPrice > 0.0) {
            ctx.storage_charge_price = avgPrice;
        }
    }

    return ctx;
}

bool DispatchService::fetchValueFromCategory(const std::string& categoryPrefix,
                                             const std::string& key,
                                             double& out) const {
    if (!dataUploader_) {
        return false;
    }

    const auto& devices = utils::Config::getInstance().getDevices();
    for (const auto& deviceCfg : devices) {
        bool hasCategory = false;
        for (const auto& modelEntry : deviceCfg.models) {
            if (!modelEntry.second.enabled) {
                continue;
            }
            if (modelEntry.first.compare(0, categoryPrefix.size(), categoryPrefix) == 0) {
                hasCategory = true;
                break;
            }
        }

        if (!hasCategory) {
            continue;
        }

        device::DataValue cached;
        if (dataUploader_->tryGetCachedValue(deviceCfg.id, key, cached) && cached.valid) {
            out = cached.value;
            return true;
        }
    }

    return false;
}

StorageState DispatchService::mapStorageStateFromRaw(int rawState) {
    switch (rawState) {
        case 1: return StorageState::Charging;
        case 2: return StorageState::Discharging;
        default: return StorageState::Idle;
    }
}

StorageWindow DispatchService::deriveWindowFromState(StorageState state) {
    switch (state) {
        case StorageState::Charging: return StorageWindow::ChargeWindow;
        case StorageState::Discharging: return StorageWindow::DischargeWindow;
        default: return StorageWindow::IdleWindow;
    }
}

void DispatchService::setEnabled(bool enabled) {
    bool previous = enabled_.exchange(enabled);
    if (previous != enabled) {
        utils::Config::getInstance().setDispatchEnabled(enabled);
        LOG_INFO("DispatchService " << (enabled ? "enabled" : "disabled") << " via web control");
        if (!enabled) {
            std::lock_guard<std::mutex> lock(dataMutex_);
            lastAction_.actions.clear();
            lastAction_.actions.push_back(DispatchActionCode::IdleAll);
            lastAction_.trace.clear();
            lastAction_.trace.push_back("调度已关闭");
        }
    }
}

// 根据上下文 ctx 生成调度动作列表
// 根据调度上下文生成动作列表
// ctx: 由采集数据拼装的调度上下文，功率单位均为 kW，电价单位为元/千瓦时

DispatchAction DispatchService::evaluate(const DispatchContext& ctx) {
    DispatchAction result;
    result.actions.clear();
    result.trace.clear();

    auto add = [&](DispatchActionCode code) {
        appendAction(result.actions, code);
    };

    auto mark = [&](const std::string& key, const std::string& value) {
        result.trace.push_back(key + ":" + value);
    };

    constexpr double kEps = 1e-6;
    const double load = ctx.load_power_kw;
    const double pv = ctx.pv_power_kw;
    const double chargeCap = ctx.storage_charge_cap_kw;
    const double dischargeCap = ctx.storage_discharge_cap_kw;

    auto ge = [&](double lhs, double rhs) { return lhs >= rhs - kEps; };
    auto le = [&](double lhs, double rhs) { return lhs <= rhs + kEps; };

    const bool load_ge_pv = ge(load, pv);
    const bool grid_ge_pv_price = ctx.grid_price_now >= ctx.pv_feed_price;

    const bool charge_available = chargeCap > kEps;
    const bool discharge_available = dischargeCap > kEps;

    const bool charge_covers_pv = charge_available && ge(chargeCap, pv);
    const bool load_plus_charge_ge_pv = charge_available && ge(load + chargeCap, pv);
    const bool load_plus_charge_le_pv = charge_available && le(load + chargeCap, pv);

    const bool storage_covers_load = discharge_available && ge(dischargeCap, load);
    const bool pv_plus_storage_ge_load = discharge_available && ge(pv + dischargeCap, load);
    const bool pv_plus_storage_le_load = discharge_available && le(pv + dischargeCap, load);

    auto ensureStoreAll = [&]() { add(DispatchActionCode::StoreAllPv); };
    auto ensureStorePart = [&]() { add(DispatchActionCode::StorePartPv); };
    auto ensureSelfUse = [&]() { add(DispatchActionCode::SelfUseAllPv); };
    auto ensureFeed = [&]() { add(DispatchActionCode::FeedExcessPv); };
    auto ensureGrid = [&]() { add(DispatchActionCode::GridSupplyLoad); };
    auto ensureFullDischarge = [&]() { add(DispatchActionCode::StorageDischargeFull); };
    auto ensureControlDischarge = [&]() { add(DispatchActionCode::StorageDischargeControl); };
    auto ensurePauseCharge = [&]() {
        add(DispatchActionCode::PauseStorageCharge);
        mark("charge_control", "pause_charge");
    };
    auto ensurePauseDischarge = [&]() { add(DispatchActionCode::PauseStorageDischarge); };

    if (load_ge_pv) {
        mark("load_ge_pv", "true");
        mark("grid_ge_pv_price", grid_ge_pv_price ? "true" : "false");

        if (grid_ge_pv_price) {
            mark("is_peak_period", ctx.is_peak_period ? "true" : "false");

            auto handleHighPriceCharge = [&](bool pause) {
                mark("storage_window", "charge");
                if (pause) {
                    ensurePauseCharge();
                    ensureSelfUse();
                    ensureGrid();
                    return;
                }
                if (!charge_available) {
                    mark("charge_capacity", "partial");
                    ensureSelfUse();
                    ensureGrid();
                    return;
                }
                if (charge_covers_pv) {
                    mark("charge_capacity", "all");
                    ensureStoreAll();
                    ensureGrid();
                } else {
                    mark("charge_capacity", "partial");
                    ensureStorePart();
                    ensureGrid();
                }
            };

            auto handleHighPriceDischarge = [&]() {
                mark("storage_window", "discharge");
                if (!discharge_available) {
                    mark("storage_discharge_capacity", "partial");
                    ensureSelfUse();
                    ensureGrid();
                    return;
                }
                if (pv_plus_storage_le_load) {
                    mark("storage_discharge_capacity", "partial");
                    ensureFullDischarge();
                    ensureSelfUse();
                    ensureGrid();
                } else {
                    mark("storage_discharge_capacity", "enough");
                    if (ctx.storage_charge_price >= ctx.pv_feed_price) {
                        mark("storage_cost_vs_pv", "higher");
                        ensureControlDischarge();
                        ensureSelfUse();
                    } else {
                        mark("storage_cost_vs_pv", "lower");
                        ensureFullDischarge();
                        ensureSelfUse();
                        ensureFeed();
                    }
                }
            };

            auto handleHighPriceIdle = [&]() {
                mark("storage_window", "idle");
                ensureSelfUse();
                ensureGrid();
            };

            if (!ctx.is_peak_period) {
                switch (ctx.storage_window) {
                    case StorageWindow::ChargeWindow:
                        handleHighPriceCharge(false);
                        break;
                    case StorageWindow::DischargeWindow:
                        handleHighPriceDischarge();
                        break;
                    case StorageWindow::IdleWindow:
                        handleHighPriceIdle();
                        break;
                }
            } else {
                switch (ctx.storage_window) {
                    case StorageWindow::ChargeWindow:
                        handleHighPriceCharge(true);
                        break;
                    case StorageWindow::DischargeWindow:
                        handleHighPriceDischarge();
                        break;
                    case StorageWindow::IdleWindow:
                        handleHighPriceIdle();
                        break;
                }
            }
        } else {
            mark("is_peak_period", ctx.is_peak_period ? "true" : "false");

            auto handleChargeFeedAll = [&]() {
                mark("storage_window", "charge");
                ensurePauseCharge();
                ensureFeed();
                ensureGrid();
            };

            auto handleDischargeFeedAll = [&]() {
                mark("storage_window", "discharge");
                if (!discharge_available) {
                    mark("storage_discharge_capacity", "partial");
                    ensureFeed();
                    ensureGrid();
                    return;
                }
                if (storage_covers_load) {
                    mark("storage_discharge_capacity", "enough");
                    ensureControlDischarge();
                    ensureFeed();
                } else {
                    mark("storage_discharge_capacity", "partial");
                    ensureFullDischarge();
                    ensureFeed();
                    ensureGrid();
                }
            };

            auto handleIdleFeedAll = [&]() {
                mark("storage_window", "idle");
                ensureFeed();
                ensureGrid();
            };

            if (!ctx.is_peak_period) {
                const bool peak_ge_pv_price = ctx.grid_price_peak >= ctx.pv_feed_price;
                mark("grid_peak_vs_pv", peak_ge_pv_price ? "higher_or_equal" : "lower");

                switch (ctx.storage_window) {
                    case StorageWindow::ChargeWindow:
                        handleChargeFeedAll();
                        break;
                    case StorageWindow::DischargeWindow:
                        handleDischargeFeedAll();
                        break;
                    case StorageWindow::IdleWindow:
                        handleIdleFeedAll();
                        break;
                }
            } else {
                switch (ctx.storage_window) {
                    case StorageWindow::ChargeWindow:
                        handleChargeFeedAll();
                        break;
                    case StorageWindow::DischargeWindow:
                        handleDischargeFeedAll();
                        break;
                    case StorageWindow::IdleWindow:
                        handleIdleFeedAll();
                        break;
                }
            }
        }
    } else {
        mark("load_ge_pv", "false");
        mark("grid_ge_pv_price", grid_ge_pv_price ? "true" : "false");

        auto handleChargeHighPriceOffPeak = [&]() {
            mark("storage_window", "charge");
            if (!charge_available) {
                mark("charge_capacity", "partial");
                ensureSelfUse();
                ensureFeed();
                return;
            }
            if (charge_covers_pv) {
                mark("charge_capacity", "all");
                ensureStoreAll();
            } else if (load_plus_charge_ge_pv) {
                mark("charge_capacity", "partial_cover");
                ensureStorePart();
                ensureSelfUse();
            } else {
                mark("charge_capacity", "excess");
                ensureStorePart();
                ensureSelfUse();
                ensureFeed();
            }
        };

        auto handleChargeHighPricePeak = [&]() {
            mark("storage_window", "charge");
            if (!charge_available) {
                mark("charge_capacity", "partial_cover");
                ensureSelfUse();
                return;
            }
            if (load_plus_charge_le_pv) {
                mark("charge_capacity", "excess");
                ensureSelfUse();
                ensureStorePart();
                ensureFeed();
            } else {
                mark("charge_capacity", "partial_cover");
                ensureSelfUse();
                ensureStorePart();
            }
        };

        auto handleDischargeHighPrice = [&]() {
            mark("storage_window", "discharge");
            if (ctx.storage_charge_price >= ctx.pv_feed_price) {
                mark("storage_cost_vs_pv", "higher");
                ensurePauseDischarge();
                ensureSelfUse();
                ensureFeed();
                return;
            }
            mark("storage_cost_vs_pv", "lower");
            if (!discharge_available) {
                mark("storage_discharge_capacity", "partial");
                ensureSelfUse();
                ensureFeed();
                return;
            }
            if (storage_covers_load) {
                mark("storage_discharge_capacity", "enough");
                ensureControlDischarge();
                ensureFeed();
            } else {
                mark("storage_discharge_capacity", "partial");
                ensureFullDischarge();
                ensureSelfUse();
                ensureFeed();
            }
        };

        auto handleIdleHighPrice = [&]() {
            mark("storage_window", "idle");
            ensureSelfUse();
            ensureFeed();
        };

        if (grid_ge_pv_price) {
            mark("is_peak_period", ctx.is_peak_period ? "true" : "false");
            if (!ctx.is_peak_period) {
                switch (ctx.storage_window) {
                    case StorageWindow::ChargeWindow:
                        handleChargeHighPriceOffPeak();
                        break;
                    case StorageWindow::DischargeWindow:
                        handleDischargeHighPrice();
                        break;
                    case StorageWindow::IdleWindow:
                        handleIdleHighPrice();
                        break;
                }
            } else {
                switch (ctx.storage_window) {
                    case StorageWindow::ChargeWindow:
                        handleChargeHighPricePeak();
                        break;
                    case StorageWindow::DischargeWindow:
                        handleDischargeHighPrice();
                        break;
                    case StorageWindow::IdleWindow:
                        handleIdleHighPrice();
                        break;
                }
            }
        } else {
            mark("is_peak_period", ctx.is_peak_period ? "true" : "false");

            auto handleDischargeLowPrice = [&]() {
                mark("storage_window", "discharge");
                if (!discharge_available) {
                    mark("storage_discharge_capacity", "partial");
                    ensureFeed();
                    return;
                }
                if (storage_covers_load) {
                    mark("storage_discharge_capacity", "enough");
                    ensureControlDischarge();
                    ensureFeed();
                } else {
                    mark("storage_discharge_capacity", "partial");
                    ensureFullDischarge();
                    ensureFeed();
                    ensureGrid();
                }
            };

            auto handleIdleLowPrice = [&]() {
                mark("storage_window", "idle");
                ensureFeed();
            };

            if (!ctx.is_peak_period) {
                const bool peak_ge_pv_price = ctx.grid_price_peak > ctx.pv_feed_price + kEps;
                mark("grid_peak_vs_pv", peak_ge_pv_price ? "higher" : "lower_or_equal");

                switch (ctx.storage_window) {
                    case StorageWindow::ChargeWindow:
                        if (peak_ge_pv_price) {
                            mark("storage_window", "charge");
                            if (!charge_available) {
                                mark("charge_capacity", "partial");
                                ensureFeed();
                            } else if (charge_covers_pv) {
                                mark("charge_capacity", "all");
                                ensureStoreAll();
                            } else {
                                mark("charge_capacity", "partial");
                                ensureStorePart();
                                ensureFeed();
                            }
                        } else {
                            mark("storage_window", "charge");
                            ensurePauseCharge();
                            ensureFeed();
                        }
                        break;
                    case StorageWindow::DischargeWindow:
                        handleDischargeLowPrice();
                        break;
                    case StorageWindow::IdleWindow:
                        handleIdleLowPrice();
                        break;
                }
            } else {
                switch (ctx.storage_window) {
                    case StorageWindow::ChargeWindow:
                        mark("storage_window", "charge");
                        ensurePauseCharge();
                        ensureFeed();
                        break;
                    case StorageWindow::DischargeWindow:
                        handleDischargeLowPrice();
                        break;
                    case StorageWindow::IdleWindow:
                        handleIdleLowPrice();
                        break;
                }
            }
        }
    }

    if (result.actions.empty()) {
        add(DispatchActionCode::IdleAll);
    }

    result.storageCommand = deriveStorageDeviceCommand(result.actions);

    return result;
}
// 将新的调度动作附加到列表中，避免重复
// 将动作附加到输出序列
// list: 当前动作序列；code: 待写入的动作枚举
void DispatchService::appendAction(std::vector<DispatchActionCode>& list, DispatchActionCode code) {
    // 使用去重逻辑确保动作序列中不会出现重复命令
    if (std::find(list.begin(), list.end(), code) == list.end()) {
        list.push_back(code);
    }
}

std::string toString(StorageWindow window) {
    switch (window) {
        case StorageWindow::ChargeWindow: return "ChargeWindow";
        case StorageWindow::DischargeWindow: return "DischargeWindow";
        case StorageWindow::IdleWindow: return "IdleWindow";
    }
    return "Unknown";
}

std::string toString(StorageState state) {
    switch (state) {
        case StorageState::Charging: return "Charging";
        case StorageState::Discharging: return "Discharging";
        case StorageState::Idle: return "Idle";
    }
    return "Unknown";
}

std::string toString(DispatchActionCode action) {
    switch (action) {
        case DispatchActionCode::SelfUseAllPv: return "SelfUseAllPv";
        case DispatchActionCode::StoreAllPv: return "StoreAllPv";
        case DispatchActionCode::StorePartPv: return "StorePartPv";
        case DispatchActionCode::FeedExcessPv: return "FeedExcessPv";
        case DispatchActionCode::GridSupplyLoad: return "GridSupplyLoad";
        case DispatchActionCode::StorageDischargeFull: return "StorageDischargeFull";
        case DispatchActionCode::StorageDischargeControl: return "StorageDischargeControl";
        case DispatchActionCode::PauseStorageCharge: return "PauseStorageCharge";
        case DispatchActionCode::PauseStorageDischarge: return "PauseStorageDischarge";
        case DispatchActionCode::IdleAll: return "IdleAll";
    }
    return "Unknown";
}

std::string toString(const DispatchAction& action) {
    std::ostringstream oss;
    oss << "[";
    for (size_t i = 0; i < action.actions.size(); ++i) {
        oss << toString(action.actions[i]);
        if (i + 1 < action.actions.size()) {
            oss << ", ";
        }
    }
    oss << "]";
    return oss.str();
}

std::string toString(StorageDeviceCommand command) {
    switch (command) {
        case StorageDeviceCommand::Start: return "Start";
        case StorageDeviceCommand::Stop: return "Stop";
        case StorageDeviceCommand::None:
        default: return "None";
    }
}

}  // namespace service
}  // namespace ems
